package top.shiyiri.list;

import org.junit.Test;
import top.shiyiri.collection.Person;

import java.util.*;

/**
 * @author Aunean
 * @date 2022/1/5
 */
/*
List接口：存储有序的、可重复的数据
    ArrayList：List 接口的主要实现类：线程不安全的，效率高；底层使用 Object[] elementData存储
    LinkedList：对于频繁的插入、删除操作，使用此类效率比 ArrayList 高；底层使用双向链表存储：
    Vector：作为 List 接口古老实现类；线程安全的，效率低；底层使用 Object[] elementData存储

ArrayList的源码分析：
JDK7.0情况下：
    ArrayList list = new ArrayList();//底层创建了长度是 10 的 Object[] 数组 elementData
    如果添加导致底层 elementData 数组容量不够，则扩容。
    默认情况下，扩容为原来的容量的 1.5 倍，同时需要将原有数组中的数据复制到新的数组中。
    结论：建议开发中使用带参的构造器
JDK8.0情况下：
    ArrayList list = new ArrayList();//底层 Object[] elementData 初始化为 {}，并没有创建长度为 10 的数组
小结：JDK7中的ArrayList对象的创建类似于单例的饿汉式，而JDK8中的ArrayList的对象的
    创建类似于单例的懒汉式，延迟了数组的创建，节省内存。

LinkedList源码分析：
LinkedList list = new LinkedList();内部声明了Node类型的first和last属性，默认值为 null
list.add(123);//将123封装到Node中，创建了Node对象
其中，Node定义为：体现了LinkedList的双向链表的说法
private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
}

Vector的源码分析：Vector()构造器创建对象时，底层都创建了长度为 10 的数组。
  在扩容方面，默认扩容为原来的数组长度的2倍

ArrayList常用方法：
增：add(Object obj)
删：remove(int index) / remove(Object obj)
改：set(int index, Object ele)
查：get(int index)
插：add(int index, Object ele)
长度：size()
遍历：Iterator迭代器、增强 for 循环

面试题：ArrayList、LinkedList、Vector 三者的异同？
同：三个都实现了 List 接口，存储数据的特点相同；存储有序的、可重复的数据
 */
public class ListTest {

    ArrayList<Object> list = new ArrayList<>();
    {
        list.add(123);
        list.add(456);
        list.add("AA");
        list.add(new Person("Tom", 12));
        list.add(456);
    }
    /*
    void add(int index, Object ele):在index位置插入ele元素
    boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
    Object get(int index):获取指定index位置的元素
    int indexOf(Object obj):返回obj在集合中首次出现的位置
    int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
    Object remove(int index):移除指定index位置的元素，并返回此元素
    Object set(int index, Object ele):设置指定index位置的元素为ele
    List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
     */
    @Test
    public void test1() {

        System.out.println(list);//[123, 456, AA, Person(name=Tom, age=12), 456]

        //void add(int index, Object ele):在index位置插入ele元素
        list.add(1, "BB");//[123, BB, 456, AA, Person(name=Tom, age=12), 456]
        System.out.println(list);

        //boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
        List<Object> list1 = Arrays.asList(1, 2, 3);
        list.addAll(list1);
        System.out.println(list);
        System.out.println(list.size());//9

        //Object get(int index):获取指定index位置的元素
        System.out.println(list.get(0));
    }

    @Test
    public void test2() {

        System.out.println(list);//[123, 456, AA, Person(name=Tom, age=12), 456]

        //int indexOf(Object obj):返回obj在集合中首次出现的位置
        System.out.println(list.indexOf("BB"));//-1
        System.out.println(list.indexOf("AA"));//2

        //int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
        System.out.println(list.lastIndexOf(456));

        //Object remove(int index):移除指定index位置的元素，并返回此元素
        Object remove = list.remove(0);
        System.out.println(remove);//123
        System.out.println(list);//[456, AA, Person(name=Tom, age=12), 456]

        //Object set(int index, Object ele):设置指定index位置的元素为ele
        list.set(1, "CC");
        System.out.println(list);//[456, CC, Person(name=Tom, age=12), 456]

        //List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
        List<Object> objects = list.subList(1, 4);
        System.out.println(objects);//[CC, Person(name=Tom, age=12), 456]
    }

    @Test
    public void test3() {

        Iterator<Object> iterator = list.iterator();
        for (;iterator.hasNext();) {
            System.out.println(iterator.next());
        }

        for (Object i: list) {
            System.out.println(i);
        }
    }

    @Test
    public void test4() {
        LinkedList<Object> list = new LinkedList<>();
        list.add(123);
        list.add(456);
        list.add("AA");
        list.add(new Person("Tom", 12));
        list.add(456);

        System.out.println(list);//[123, 456, AA, Person(name=Tom, age=12), 456]

        //void addFirst(Object obj)：在集合的首位添加元素
        list.addFirst(12);
        System.out.println(list);//[12, 123, 456, AA, Person(name=Tom, age=12), 456]

        //void addLast(Object obj)：在集合末尾添加元素
        list.addLast("ABC");
        System.out.println(list);//[12, 123, 456, AA, Person(name=Tom, age=12), 456, ABC]

        //Object getFirst()：获取集合首位的元素
        Object first = list.getFirst();
        System.out.println(first);//12

        //Object getLast()：获取集合末位的元素
        Object last = list.getLast();
        System.out.println(last);//ABC

        //Object removeFirst()：删除集合中首位的元素
        list.removeFirst();
        System.out.println(list);//[123, 456, AA, Person(name=Tom, age=12), 456, ABC]

        //Object removeLast()：删除集合中末尾的元素
        list.removeLast();
        System.out.println(list);//[123, 456, AA, Person(name=Tom, age=12), 456]
    }

}
